/*
 * Copyright (c) 2012 Jonathan Tyers
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package uk.org.uplink.configproxy.guice;

import java.io.File;
import java.net.URL;

import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.HierarchicalConfiguration;

import uk.org.uplink.configproxy.ConfigProxyFactory;

import com.google.inject.Binder;
import com.google.inject.Module;
import com.google.inject.Provider;

/**
 * Provides methods for binding config proxies inside {@link Module Guice modules}.
 * <p>
 * Example usage:
 * <pre>
 * import static uk.org.uplink.configproxy.guice.ConfigProxyBinder.bindConfigurationClass;
 * 
 * public class MyModule extends AbstractModule {
 *   protected void configure() {
 *     bindConfigurationClass(binder(), MyConfiguration.class).withXmlFile("/path/to/config.xml");
 *   }
 * }
 * </pre>
 * This code will enable Guice to inject instances of <tt>MyConfiguration</tt>, pointing to <tt>config.xml</tt>.
 * 
 * @author jonny
 */
public class ConfigProxyBinder {
	public static class ConfigProxyBinderBuilder<T> {
		private final Binder binder;

		private final Class<T> configurationInterface;

		public ConfigProxyBinderBuilder(final Binder binder, final Class<T> configurationInterface) {
			super();
			this.binder = binder;
			this.configurationInterface = configurationInterface;
		}

		public void withXmlFile(final String xmlFile) {
			binder.bind(configurationInterface).toProvider(new Provider<T>() {
				@Override
				public T get() {
					try {
						return ConfigProxyFactory.createConfigProxyFromXml(configurationInterface, xmlFile);
					} catch (ConfigurationException e) {
						binder.addError(e);
						return null;
					}
				}
			});
		}

		public void withXmlFile(final File xmlFile) {
			binder.bind(configurationInterface).toProvider(new Provider<T>() {
				@Override
				public T get() {
					try {
						return ConfigProxyFactory.createConfigProxyFromXml(configurationInterface, xmlFile);
					} catch (ConfigurationException e) {
						binder.addError(e);
						return null;
					}
				}
			});
		}

		public void withXmlFile(final URL xmlFile) {
			binder.bind(configurationInterface).toProvider(new Provider<T>() {
				@Override
				public T get() {
					try {
						return ConfigProxyFactory.createConfigProxyFromXml(configurationInterface, xmlFile);
					} catch (ConfigurationException e) {
						binder.addError(e);
						return null;
					}
				}
			});
		}

		public void withConfiguration(final HierarchicalConfiguration configuration) {
			binder.bind(configurationInterface).toProvider(new Provider<T>() {
				@Override
				public T get() {
					return ConfigProxyFactory.createConfigProxyFromConfiguration(configurationInterface, configuration);
				}
			});
		}
	}

	public static <T> ConfigProxyBinderBuilder<T> bindConfigurationClass(final Binder binder, final Class<T> configurationInterface) {
		return new ConfigProxyBinderBuilder<T>(binder, configurationInterface);
	}
}
